/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现角色镜头的旋转控制
* CreateTime：2020-05-11 10:20:46
* Version：1.0
* Modify Recorder：
*************************************************/

using System;
using UnityEngine;

namespace TinyToolKit
{
    [Serializable]
    public class MouseCtr
    {
        [Range(0,2)] public int mouseBtn;
        public float xSensitivity = 2f;
        public float ySensitivity = 2f;
        public bool clampVerticalRotation = true;
        public float minX = -90f;
        public float maxX = 90f;
        public bool smooth;
        public float smoothTime = 5f;
        public bool lockCursor = true;

        private Quaternion _characterTargetRot;
        private Quaternion _cameraTargetRot;
        private bool _cursorIsLocked = true;

        public void Init(Transform character, Transform camera)
        {
            _characterTargetRot = character.rotation;
            _cameraTargetRot = camera.localRotation;
        }

        public void LookRotation(Transform character, Transform camera)
        {
            if (Input.GetMouseButton(mouseBtn) == false) return; 
            
            float yRot = Input.GetAxis("Mouse X") * xSensitivity;
            float xRot = Input.GetAxis("Mouse Y") * ySensitivity;

            _characterTargetRot *= Quaternion.Euler(0, yRot, 0);
            _cameraTargetRot *= Quaternion.Euler(-xRot, 0, 0);

            if (clampVerticalRotation)
                _cameraTargetRot = ClampRotationAroundAxis(_cameraTargetRot);

            if (smooth)
            {
                character.localRotation = Quaternion.Slerp(character.localRotation, _characterTargetRot,
                    smoothTime * Time.deltaTime);
                camera.localRotation = Quaternion.Slerp(camera.localRotation,_cameraTargetRot,smoothTime * Time.deltaTime);
            }
            else
            {
                character.localRotation = _characterTargetRot;
                camera.localRotation = _cameraTargetRot;
            }
            
            UpdateCursorLock();
        }

        public void SetCursorLock(bool value)
        {
            lockCursor = value;
            if (!lockCursor)
            {
                Cursor.lockState = CursorLockMode.None;
                Cursor.visible = true;
            }
            else
            {
                Cursor.lockState = CursorLockMode.Locked;
                Cursor.visible = false;
            }
        }

        private void UpdateCursorLock()
        {
            if (lockCursor)
                InternalLockUpdate();
        }

        private void InternalLockUpdate() 
        {
            if (Input.GetKeyUp(KeyCode.Escape))
            {
                _cursorIsLocked = false;
            }
            else if (Input.GetMouseButtonUp(0))
            {
                _cursorIsLocked = true;
            }

            if (_cursorIsLocked)
            {
                Cursor.lockState = CursorLockMode.Locked;
                Cursor.visible = false;
            }
            else
            {
                Cursor.lockState = CursorLockMode.None;
                Cursor.visible = true;
            }
        }

        private Quaternion ClampRotationAroundAxis(Quaternion qua)
        {
            qua.x /= qua.w;
            qua.y /= qua.w;
            qua.z /= qua.w;
            qua.w = 1;

            float angleX = 2 * Mathf.Rad2Deg * Mathf.Atan(qua.x);
            angleX = Mathf.Clamp(angleX, minX, maxX);
            qua.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
            return qua;
        }
    }
}